package com.yzs.core.base

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.yzs.core.bean.NetworkViewState
import com.yzs.core.bean.PageStatus
import com.yzs.core.ext.asLiveData
import com.yzs.core.http.ApiException
import kotlinx.coroutines.*
import org.json.JSONException
import retrofit2.HttpException
import java.net.ConnectException
import java.net.SocketException
import java.net.SocketTimeoutException
import java.net.UnknownHostException

/**
 *    author : yzs
 *    date   : 2022/1/1211:50
 *    desc   :
 */
open class BaseViewModel : ViewModel() {
    /**
     * 页面请求 liveData 统一监听  loading
     */
    protected val _viewStates = MutableLiveData(NetworkViewState())
    val liveDataViewStates = _viewStates.asLiveData()


    protected fun <T> launch(
        block: suspend () -> T,
        success: suspend (T) -> Unit,
        error: ApiError? = null
    ): Job {
        _viewStates.postValue(NetworkViewState("加载中...", PageStatus.LOADING))
        return viewModelScope.launch {
            runCatching {
                withContext(Dispatchers.IO) {
                    block()
                }
            }.onSuccess {
                runCatching {
                    success(it)
                    _viewStates.value = NetworkViewState("加载成功", PageStatus.LOADING)
                }.onFailure {
                    it.printStackTrace()
                    val e = ApiException("数据转换异常", -1)
                    error?.invoke(e)
                    _viewStates.value = NetworkViewState("数据转换异常", PageStatus.FAILURE(e))
                }
            }.onFailure {
                it.printStackTrace()
                getApiException(it).apply {
                    error?.invoke(this)
                    // 可以做统一提示处理
                    // Toast
                    // 统一响应错误信息
                    _viewStates.value =
                        NetworkViewState(this.errorMessage, PageStatus.FAILURE(this))
                }
            }
        }
    }

    /**
     * 捕获异常信息
     */
    private fun getApiException(e: Throwable): ApiException {
        val apiException = when (e) {
            is UnknownHostException -> {
                ApiException("网络异常，请检查网络", -100)
            }
            is SocketException -> {
                ApiException("网络异常，请检查网络手机是否可以上网", -100)
            }
            is JSONException -> {
                ApiException("数据异常", -100)
            }
            is SocketTimeoutException -> {
                ApiException("连接超时", -100)
            }
            is ConnectException -> {
                ApiException("无法连接服务器", -100)
            }
            is HttpException -> {
                ApiException(e.message(), e.code())
            }
            is ApiException -> {
                e
            }
            /**
             * 如果协程还在运行，个别机型退出当前界面时，viewModel会通过抛出CancellationException，
             * 强行结束协程，与java中InterruptException类似，所以不必理会,只需将toast隐藏即可
             */
            is CancellationException -> {
                ApiException("", -10)
            }
            else -> {
                ApiException("未知错误", -100)
            }
        }
        return apiException
    }


}